// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:io';

extension TestGeneratorStringExtension on String {
  String upperCaseFirst() => "${this[0].toUpperCase()}${this.substring(1)}";

  String lowerCaseFirst() => "${this[0].toLowerCase()}${this.substring(1)}";

  String makeCComment() => "// " + split("\n").join("\n// ");

  String makeDartDocComment() => "/// " + split("\n").join("\n/// ");

  String limitTo(int length) {
    if (this.length > length) {
      return substring(0, length);
    }
    return this;
  }

  String trimCouts() => replaceAll('" << "', '').replaceAll('"<< "', '');
}

Future<void> runProcess(String executable, List<String> arguments) async {
  final commandString = [executable, ...arguments].join(' ');
  stdout.writeln('Running `$commandString`.');
  final process =
      await Process.start(
        executable,
        arguments,
        runInShell: true,
        includeParentEnvironment: true,
      ).then((process) {
        process.stdout.forEach(stdout.add);
        process.stderr.forEach(stderr.add);
        return process;
      });
  final exitCode = await process.exitCode;
  if (exitCode != 0) {
    final message = 'Command `$commandString` failed with exit code $exitCode.';
    stderr.writeln(message);
    throw Exception(message);
  }
  stdout.writeln('Command `$commandString` done.');
}

String headerCommon({
  required int copyrightYear,
  required String generatorPath,
}) {
  final year = copyrightYear;
  return """
// Copyright (c) $year, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// This file has been automatically generated. Please do not edit it manually.
// Generated by $generatorPath.""";
}

String headerC({required int copyrightYear, required String generatorPath}) {
  return """
${headerCommon(copyrightYear: copyrightYear, generatorPath: generatorPath)}

#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>

#include <cmath>
#include <iostream>
#include <limits>

#if defined(_WIN32)
#define DART_EXPORT extern "C" __declspec(dllexport)
#else
#define DART_EXPORT                                                            \\
  extern "C" __attribute__((visibility("default"))) __attribute((used))
#endif

namespace dart {

#define CHECK(X)                                                               \\
  if (!(X)) {                                                                  \\
    fprintf(stderr, "%s\\n", "Check failed: " #X);                              \\
    return 1;                                                                  \\
  }

#define CHECK_EQ(X, Y) CHECK((X) == (Y))

// Works for positive, negative and zero.
#define CHECK_APPROX(EXPECTED, ACTUAL)                                         \\
  CHECK(((EXPECTED * 0.99) <= (ACTUAL) && (EXPECTED * 1.01) >= (ACTUAL)) ||    \\
        ((EXPECTED * 0.99) >= (ACTUAL) && (EXPECTED * 1.01) <= (ACTUAL)))

""";
}

const footerC = """

}  // namespace dart
""";
